package repository

import (
	"fitness/go-admin/internal/model"
	"time"

	"gorm.io/gorm"
)

// CheckinRepository 签到仓储接口
type CheckinRepository interface {
	// 基础签到功能
	CreateCheckin(checkin *model.Checkin) error
	GetCheckinByID(id uint) (*model.Checkin, error)
	GetMemberTodayCheckin(memberID uint, date time.Time, typ int) (*model.Checkin, error)
	GetMemberCheckins(memberID uint, req *model.CheckinListReq) ([]model.Checkin, int64, error)
	UpdateCheckin(checkin *model.Checkin) error
	DeleteCheckin(id uint) error

	// 签退功能
	GetMemberTodayLastCheckin(memberID uint, date time.Time) (*model.Checkin, error)

	// 统计功能
	GetMemberCheckinStatistics(memberID uint, period string) (*model.CheckinStatisticsResp, error)
	GetMemberConsecutiveDays(memberID uint) (int, error)
	GetCheckinTrend(memberID uint, days int) ([]struct {
		Date     string
		Count    int
		Duration int
	}, error)

	// 前台功能
	GetStaffCheckins(req *model.StaffCheckinListReq) (*model.StaffCheckinListResp, error)
	GetTodayCheckinCount() (int, error)
	GetCurrentInGymCount() (int, error)

	// 管理员功能
	GetAdminCheckins(req *model.AdminCheckinListReq) (*model.AdminCheckinListResp, error)
	GetAdminAnalytics(req *model.AdminAnalyticsReq) (*model.AdminAnalyticsResp, error)

	// 健身房信息管理
	GetGymByID(id uint) (*model.Gym, error)
	GetAllGyms() ([]model.Gym, error)
	CreateGym(gym *model.Gym) error
	UpdateGym(gym *model.Gym) error
	DeleteGym(id uint) error

	// 批量操作
	BatchCreateCheckins(checkins []model.Checkin) error
}

type checkinRepository struct {
	db *gorm.DB
}

func NewCheckinRepository(db *gorm.DB) CheckinRepository {
	return &checkinRepository{db: db}
}

// ==================== 基础签到功能 ====================

func (r *checkinRepository) CreateCheckin(checkin *model.Checkin) error {
	return r.db.Create(checkin).Error
}

func (r *checkinRepository) GetCheckinByID(id uint) (*model.Checkin, error) {
	var checkin model.Checkin
	err := r.db.Preload("Member").Preload("User").First(&checkin, id).Error
	return &checkin, err
}

func (r *checkinRepository) GetMemberTodayCheckin(memberID uint, date time.Time, typ int) (*model.Checkin, error) {
	var checkin model.Checkin
	startOfDay := time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, date.Location())
	endOfDay := startOfDay.AddDate(0, 0, 1).Add(-time.Nanosecond)

	err := r.db.Where("member_id = ? AND type = ? AND check_in_time BETWEEN ? AND ?",
		memberID, typ, startOfDay, endOfDay).First(&checkin).Error

	if err != nil {
		return nil, err
	}
	return &checkin, nil
}

func (r *checkinRepository) GetMemberCheckins(memberID uint, req *model.CheckinListReq) ([]model.Checkin, int64, error) {
	var checkins []model.Checkin
	var total int64

	query := r.db.Model(&model.Checkin{}).Where("member_id = ?", memberID)

	// 日期范围筛选
	if req.StartDate != "" {
		startDate, err := time.Parse("2006-01-02", req.StartDate)
		if err == nil {
			query = query.Where("check_in_time >= ?", startDate)
		}
	}
	if req.EndDate != "" {
		endDate, err := time.Parse("2006-01-02", req.EndDate)
		if err == nil {
			// 结束日期加一天，以包含当天的所有记录
			endDate = endDate.AddDate(0, 0, 1)
			query = query.Where("check_in_time < ?", endDate)
		}
	}

	// 类型筛选
	if req.Type != nil {
		query = query.Where("type = ?", *req.Type)
	}

	// 统计总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 排序和分页
	offset := (req.Page - 1) * req.PageSize
	err := query.Order("check_in_time DESC").Limit(req.PageSize).Offset(offset).Find(&checkins).Error
	return checkins, total, err
}

func (r *checkinRepository) UpdateCheckin(checkin *model.Checkin) error {
	return r.db.Save(checkin).Error
}

func (r *checkinRepository) DeleteCheckin(id uint) error {
	return r.db.Delete(&model.Checkin{}, id).Error
}

// ==================== 签退功能 ====================

func (r *checkinRepository) GetMemberTodayLastCheckin(memberID uint, date time.Time) (*model.Checkin, error) {
	var checkin model.Checkin
	startOfDay := time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, date.Location())
	endOfDay := startOfDay.AddDate(0, 0, 1).Add(-time.Nanosecond)

	err := r.db.Where("member_id = ? AND check_in_time BETWEEN ? AND ? AND type = 1",
		memberID, startOfDay, endOfDay).Order("check_in_time DESC").First(&checkin).Error

	if err != nil {
		return nil, err
	}
	return &checkin, nil
}

// ==================== 统计功能 ====================

func (r *checkinRepository) GetMemberCheckinStatistics(memberID uint, period string) (*model.CheckinStatisticsResp, error) {
	// 这里实现具体的统计逻辑
	// 由于统计逻辑较为复杂，实际实现时需要根据具体需求进行调整
	resp := &model.CheckinStatisticsResp{}
	return resp, nil
}

func (r *checkinRepository) GetMemberConsecutiveDays(memberID uint) (int, error) {
	// 计算连续签到天数
	days := 0
	currentDate := time.Now()

	for {
		startOfDay := time.Date(currentDate.Year(), currentDate.Month(), currentDate.Day(), 0, 0, 0, 0, currentDate.Location())
		endOfDay := startOfDay.AddDate(0, 0, 1).Add(-time.Nanosecond)

		var count int64
		err := r.db.Model(&model.Checkin{}).
			Where("member_id = ? AND type = 1 AND check_in_time BETWEEN ? AND ?",
				memberID, startOfDay, endOfDay).
			Count(&count).Error

		if err != nil || count == 0 {
			break
		}

		days++
		currentDate = currentDate.AddDate(0, 0, -1)
	}

	return days, nil
}

func (r *checkinRepository) GetCheckinTrend(memberID uint, days int) ([]struct {
	Date     string
	Count    int
	Duration int
}, error) {
	// 获取签到趋势数据
	result := make([]struct {
		Date     string
		Count    int
		Duration int
	}, days)

	currentDate := time.Now().AddDate(0, 0, -days+1)
	for i := 0; i < days; i++ {
		dateStr := currentDate.Format("2006-01-02")
		startOfDay := time.Date(currentDate.Year(), currentDate.Month(), currentDate.Day(), 0, 0, 0, 0, currentDate.Location())
		endOfDay := startOfDay.AddDate(0, 0, 1).Add(-time.Nanosecond)

		var count int64
		r.db.Model(&model.Checkin{}).
			Where("member_id = ? AND type = 1 AND check_in_time BETWEEN ? AND ?",
				memberID, startOfDay, endOfDay).
			Count(&count)

		// 计算平均时长（分钟）
		var totalDuration int
		r.db.Model(&model.Checkin{}).
			Select("COALESCE(SUM(duration), 0)").
			Where("member_id = ? AND type = 2 AND check_in_time BETWEEN ? AND ?",
				memberID, startOfDay, endOfDay).
			Scan(&totalDuration)

		avgDuration := 0
		if count > 0 {
			avgDuration = totalDuration / int(count)
		}

		result[i] = struct {
			Date     string
			Count    int
			Duration int
		}{
			Date:     dateStr,
			Count:    int(count),
			Duration: avgDuration,
		}

		currentDate = currentDate.AddDate(0, 0, 1)
	}

	return result, nil
}

// ==================== 前台功能 ====================

func (r *checkinRepository) GetStaffCheckins(req *model.StaffCheckinListReq) (*model.StaffCheckinListResp, error) {
	resp := &model.StaffCheckinListResp{}

	// 设置默认值
	if req.Page <= 0 {
		req.Page = 1
	}
	if req.PageSize <= 0 {
		req.PageSize = 20
	}

	// 查询日期，默认今天
	queryDate := time.Now()
	if req.Date != "" {
		if parsedDate, err := time.Parse("2006-01-02", req.Date); err == nil {
			queryDate = parsedDate
		}
	}

	startOfDay := time.Date(queryDate.Year(), queryDate.Month(), queryDate.Day(), 0, 0, 0, 0, queryDate.Location())
	endOfDay := startOfDay.AddDate(0, 0, 1).Add(-time.Nanosecond)

	// 构建查询
	query := r.db.Model(&model.Checkin{}).
		Joins("LEFT JOIN members ON checkins.member_id = members.id").
		Where("checkins.check_in_time BETWEEN ? AND ?", startOfDay, endOfDay)

	// 状态筛选
	if req.Status != nil {
		switch *req.Status {
		case 1: // 已签到未签退
			query = query.Where("checkins.type = 1 AND checkins.check_out_time IS NULL")
		case 2: // 已签退
			query = query.Where("checkins.type = 2 OR checkins.check_out_time IS NOT NULL")
		}
	}

	// 关键词搜索
	if req.Keyword != "" {
		query = query.Where("members.name LIKE ? OR members.card_number LIKE ?",
			"%"+req.Keyword+"%", "%"+req.Keyword+"%")
	}

	// 统计今日总签到数
	var todayTotal int64
	r.db.Model(&model.Checkin{}).
		Where("check_ins.check_in_time BETWEEN ? AND ? AND check_ins.type = 1", startOfDay, endOfDay).
		Count(&todayTotal)
	resp.TodayTotal = int(todayTotal)

	// 统计当前在馆人数
	var inGymCount int64
	r.db.Model(&model.Checkin{}).
		Where("check_ins.check_in_time BETWEEN ? AND ? AND check_ins.type = 1 AND check_ins.check_out_time IS NULL",
			startOfDay, endOfDay).
		Count(&inGymCount)
	resp.InGymCount = int(inGymCount)

	// 查询记录
	var records []struct {
		model.Checkin
		MemberName string `json:"memberName" gorm:"column:member_name"`
		MemberCard string `json:"memberCard" gorm:"column:member_card"`
	}

	offset := (req.Page - 1) * req.PageSize
	err := query.Select("checkins.*, members.name as member_name, members.card_number as member_card").
		Order("checkins.check_in_time DESC").
		Limit(req.PageSize).
		Offset(offset).
		Find(&records).Error

	if err != nil {
		return nil, err
	}

	// 转换为响应格式
	for _, record := range records {
		status := 1 // 在馆中
		statusText := "在馆中"
		if record.CheckOutTime != nil || record.Type == 2 {
			status = 2 // 已签退
			statusText = "已签退"
		}

		duration := 0
		if record.Duration != nil {
			duration = *record.Duration
		}

		resp.Records = append(resp.Records, model.StaffCheckinRecord{
			ID:           record.ID,
			MemberID:     record.MemberID,
			MemberName:   record.MemberName,
			MemberCard:   record.MemberCard,
			CheckInTime:  record.CheckInTime,
			CheckOutTime: record.CheckOutTime,
			Duration:     duration,
			Status:       status,
			StatusText:   statusText,
		})
	}

	// 统计总数
	r.db.Model(&model.Checkin{}).
		Joins("LEFT JOIN members ON checkins.member_id = members.id").
		Where("checkins.check_in_time BETWEEN ? AND ?", startOfDay, endOfDay).
		Where("checkins.type = 1").
		Count(&resp.Total)

	return resp, nil
}

func (r *checkinRepository) GetTodayCheckinCount() (int, error) {
	var count int64
	startOfDay := time.Now().Truncate(24 * time.Hour)
	endOfDay := startOfDay.Add(24 * time.Hour).Add(-time.Nanosecond)

	err := r.db.Model(&model.Checkin{}).
		Where("type = 1 AND check_in_time BETWEEN ? AND ?", startOfDay, endOfDay).
		Count(&count).Error

	return int(count), err
}

func (r *checkinRepository) GetCurrentInGymCount() (int, error) {
	var count int64
	startOfDay := time.Now().Truncate(24 * time.Hour)
	endOfDay := startOfDay.Add(24 * time.Hour).Add(-time.Nanosecond)

	err := r.db.Model(&model.Checkin{}).
		Where("type = 1 AND check_in_time BETWEEN ? AND ? AND check_out_time IS NULL",
			startOfDay, endOfDay).
		Count(&count).Error

	return int(count), err
}

// ==================== 管理员功能 ====================

func (r *checkinRepository) GetAdminCheckins(req *model.AdminCheckinListReq) (*model.AdminCheckinListResp, error) {
	resp := &model.AdminCheckinListResp{}

	// 设置默认值
	if req.Page <= 0 {
		req.Page = 1
	}
	if req.PageSize <= 0 {
		req.PageSize = 20
	}

	// 构建查询
	query := r.db.Model(&model.Checkin{}).
		Joins("LEFT JOIN members ON checkins.member_id = members.id").
		Joins("LEFT JOIN users ON checkins.operator_id = users.id")

	// 会员ID筛选
	if req.MemberID != nil {
		query = query.Where("checkins.member_id = ?", *req.MemberID)
	}

	// 日期范围筛选
	if req.StartDate != "" {
		startDate, err := time.Parse("2006-01-02", req.StartDate)
		if err == nil {
			query = query.Where("checkins.check_in_time >= ?", startDate)
		}
	}
	if req.EndDate != "" {
		endDate, err := time.Parse("2006-01-02", req.EndDate)
		if err == nil {
			endDate = endDate.AddDate(0, 0, 1)
			query = query.Where("checkins.check_in_time < ?", endDate)
		}
	}

	// 签到地点筛选
	if req.Location != "" {
		query = query.Where("checkins.location LIKE ?", "%"+req.Location+"%")
	}

	// 类型筛选
	if req.Type != nil {
		query = query.Where("checkins.type = ?", *req.Type)
	}

	// 关键词搜索
	if req.Keyword != "" {
		query = query.Where("members.name LIKE ? OR members.card_number LIKE ?",
			"%"+req.Keyword+"%", "%"+req.Keyword+"%")
	}

	// 统计总数
	if err := query.Count(&resp.Total).Error; err != nil {
		return nil, err
	}

	// 查询记录
	var records []struct {
		model.Checkin
		MemberName   string `json:"memberName" gorm:"column:member_name"`
		MemberCard   string `json:"memberCard" gorm:"column:member_card"`
		OperatorName string `json:"operatorName" gorm:"column:operator_name"`
	}

	offset := (req.Page - 1) * req.PageSize
	err := query.Select("checkins.*, members.name as member_name, members.card_number as member_card, users.username as operator_name").
		Order("checkins.check_in_time DESC").
		Limit(req.PageSize).
		Offset(offset).
		Find(&records).Error

	if err != nil {
		return nil, err
	}

	// 转换为响应格式
	for _, record := range records {
		typeText := "进馆签到"
		if record.Type == 2 {
			typeText = "离馆签退"
		}

		var operator *string
		if record.OperatorName != "" {
			operator = &record.OperatorName
		}

		resp.List = append(resp.List, model.AdminCheckinRecord{
			ID:           record.ID,
			MemberID:     record.MemberID,
			MemberName:   record.MemberName,
			MemberCard:   record.MemberCard,
			CheckInTime:  record.CheckInTime,
			CheckOutTime: record.CheckOutTime,
			Duration:     record.Duration,
			Location:     record.Location,
			DeviceID:     record.DeviceID,
			Type:         record.Type,
			TypeText:     typeText,
			Operator:     operator,
		})
	}

	resp.Page = req.Page
	resp.PageSize = req.PageSize

	return resp, nil
}

func (r *checkinRepository) GetAdminAnalytics(req *model.AdminAnalyticsReq) (*model.AdminAnalyticsResp, error) {
	resp := &model.AdminAnalyticsResp{}

	// 设置默认值
	if req.Period == "" {
		req.Period = "month"
	}

	// 这里实现具体的统计分析逻辑
	// 由于统计分析逻辑较为复杂，实际实现时需要根据具体需求进行调整

	return resp, nil
}

// ==================== 健身房信息管理 ====================

func (r *checkinRepository) GetGymByID(id uint) (*model.Gym, error) {
	var gym model.Gym
	err := r.db.First(&gym, id).Error
	return &gym, err
}

func (r *checkinRepository) GetAllGyms() ([]model.Gym, error) {
	var gyms []model.Gym
	err := r.db.Find(&gyms).Error
	return gyms, err
}

func (r *checkinRepository) CreateGym(gym *model.Gym) error {
	return r.db.Create(gym).Error
}

func (r *checkinRepository) UpdateGym(gym *model.Gym) error {
	return r.db.Save(gym).Error
}

func (r *checkinRepository) DeleteGym(id uint) error {
	return r.db.Delete(&model.Gym{}, id).Error
}

// ==================== 批量操作 ====================

func (r *checkinRepository) BatchCreateCheckins(checkins []model.Checkin) error {
	return r.db.CreateInBatches(checkins, 100).Error
}
